package main

import "fmt"
import "errors"

// 错误通常是最后一个返回值并且是 error 类 型，一个内建的接口。errors.New 构造一个使用给定的错误信息的基本 error 值。返回错误值为 nil 代表没有错误。
// 你如果想在程序中使用一个自定义错误类型中的数据，你 需要通过类型断言来得到这个错误类型的实例。
// 本质上，Golang 中的错误类型 error 是一个接口类型：
// type error interface {
// Error() string
// }
// 理解参考 https://studygolang.com/articles/4389 | http://www.runoob.com/go/go-error-handling.html
// 任何实现了Error()方法的struct都是error类型,go中就是这么定义的(error是官方内置接口)

type argError struct {
	arg  int
	prob string
}

func (e *argError) Error() string {
	return fmt.Sprintf("%d - %s", e.arg, e.prob)
}

func f1(arg int) (int, error) {
	if arg == 42 {
		return -1, errors.New("can't work with 42")
	}
	return arg + 3, nil
}

func f2(arg int) (int, error) {
	if arg == 42 {
		return -1, &argError{arg, "can't work with it"}
	}
	return arg + 3, nil
}

func main() {
	for _, i := range []int{7, 42} {
		if r, e := f1(i); e != nil {
			fmt.Println("f1 failed:", e)
		} else {
			fmt.Println("f1 worked:", r)
		}
	}
	for _, i := range []int{7, 42} {
		if r, e := f2(i); e != nil {
			fmt.Println("f2 failed:", e)
		} else {
			fmt.Println("f2 worked:", r)
		}
	}
	_, e := f2(42)
	fmt.Println(e)
	if ae, ok := e.(*argError); ok {
		fmt.Println(ae.arg)
		fmt.Println(ae.prob)
	}
}
